package org.taobao.ibatiside.ui.wizard;

import java.beans.PropertyChangeEvent;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;

import org.apache.commons.lang.StringUtils;
import org.eclipse.core.databinding.beans.BeansObservables;
import org.eclipse.core.databinding.beans.PojoObservables;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.map.IObservableMap;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.internal.databinding.beans.BeanObservableListDecorator;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.datatools.modelbase.sql.tables.Table;
import org.eclipse.emf.databinding.EMFDataBindingContext;
import org.eclipse.jdt.core.IType;
import org.eclipse.jface.databinding.swt.ISWTObservableValue;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
import org.eclipse.jface.databinding.viewers.ObservableMapLabelProvider;
import org.eclipse.jface.databinding.viewers.ViewersObservables;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.dialogs.FilteredItemsSelectionDialog;
import org.eclipse.ui.internal.ide.dialogs.OpenResourceDialog;
import org.taobao.ibatiside.core.filemodel.FileProber;
import org.taobao.ibatiside.ui.util.JavaClassDialog;
import org.taobao.ibatiside.ui.util.MiscHelper;
import org.taobao.ibatiside.ui.util.ResourceDialog;
import org.taobao.ibatiside.ui.util.WorkspaceUtil;

public class DaoPage extends BatisCommonPage {
	private Text text_interface_path;
	private Text text_impl_path;
	private Button btnEnableInterface;
	private Button btn_create_new_interface;
	private Button btn_create_new_impl;
	private ComboViewer comboInterfaceViewer;
	private ComboViewer comboImplViewer;
	private Text textBeanId;
	private Combo comboInterface;
	private ComboViewer comboSpringTplViewer;
	private Button btnIntegrateIntoSpring;
	private Text textSpringConfig;
	public DaoPage(String pageName) {
		super(pageName);
		setDescription("Generate DAO to access iBATIS statement");
		setTitle("DAO");
	}
	@Override
	public boolean isPageComplete() {
		if (!model.getDaoPageRequired()) return true;
		return model.getDaoImplementationPath() != null && model.getDaoImplTemplate() != null &&
				(!model.getDaoNeedInterface() || (model.getDaoInterfacePath() != null && model.getDaoInterfaceTemplate() != null)) &&
				(!model.getSpringIntegrate() || (StringUtils.isNotBlank(model.getSpringBeanId()) && model.getSpringConfiguration() != null && model.getSpringTemplate() !=null));
	}
	@Override
	public void propertyChange(PropertyChangeEvent evt) {
		super.propertyChange(evt);
		String pn = evt.getPropertyName();
		if (BatisSettingModel.K_DAO_INTERFACE_PATH.equals(pn)){
			IPath path = (IPath) evt.getNewValue();
			text_interface_path.setText(path == null? "" : path.toString());
		}else if (BatisSettingModel.K_DAO_IMPLEMENTATION_PATH.equals(pn)){
			IPath path = (IPath) evt.getNewValue();
			text_impl_path.setText(path == null ? "" : path.toString());
		}else if (BatisSettingModel.K_DAO_CREATE_NEW_INTERFACE.equals(pn)){
			
		}else if (BatisSettingModel.K_SPRING_INTEGRATE.equals(pn)){
			boolean need_spring = ((Boolean)evt.getNewValue()).booleanValue();
		}else if (BatisSettingModel.K_DAO_INTERFACE_TEMPLATES.equals(pn)){
			Object new_list = evt.getNewValue();
			comboInterfaceViewer.setInput(new_list);
			if (model.getDaoInterfaceTemplate() != null){
				comboInterfaceViewer.setSelection(new StructuredSelection(model.getDaoInterfaceTemplate()),true);
			}
		}else if (BatisSettingModel.K_DAO_IMPL_TEMPLATES.equals(pn)){
			Object new_list = evt.getNewValue();
			comboImplViewer.setInput(new_list);
			if (model.getDaoImplTemplate() != null){
				comboImplViewer.setSelection(new StructuredSelection(model.getDaoImplTemplate()), true);
			}
		}
	}
	
	@Override
	public void dispose() {
		super.dispose();
	}

	@Override
	public void doCreateControl(Composite parent) {
		Composite container = new Composite(parent, SWT.NULL);
		setControl(container);
		container.setLayout(new GridLayout(1, false));
		
		Group grpDaoSettings = new Group(container, SWT.NONE);
		FormLayout fl_grpDaoSettings = new FormLayout();
		fl_grpDaoSettings.spacing = 1;
		grpDaoSettings.setLayout(fl_grpDaoSettings);
		GridData gd_grpDaoSettings = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
		gd_grpDaoSettings.heightHint = 120;
		grpDaoSettings.setLayoutData(gd_grpDaoSettings);
		grpDaoSettings.setText("DAO Settings");
		
		btnEnableInterface = new Button(grpDaoSettings, SWT.CHECK);
		FormData fd_btnEnableInterface = new FormData();
		fd_btnEnableInterface.top = new FormAttachment(0, 10);
		fd_btnEnableInterface.left = new FormAttachment(0, 50);
		fd_btnEnableInterface.right = new FormAttachment(100);
		btnEnableInterface.setLayoutData(fd_btnEnableInterface);
		btnEnableInterface.setText("Generate Interface");
		
		Label lblInterface = new Label(grpDaoSettings, SWT.RIGHT);
		FormData fd_lblInterface = new FormData();
		fd_lblInterface.top = new FormAttachment(btnEnableInterface, 10);
		fd_lblInterface.left = new FormAttachment(0,0);
		fd_lblInterface.right = new FormAttachment(0,100);
		lblInterface.setLayoutData(fd_lblInterface);
		lblInterface.setText("Interface");
		
		text_interface_path = new Text(grpDaoSettings, SWT.BORDER);
		FormData fd_text_interface_path = new FormData();
		fd_text_interface_path.top = new FormAttachment(btnEnableInterface, 6);
		fd_text_interface_path.left = new FormAttachment(lblInterface,10);
		fd_text_interface_path.right = new FormAttachment(65);
		text_interface_path.setLayoutData(fd_text_interface_path);
		text_interface_path.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseDoubleClick(MouseEvent e) {
				if (model.getDaoCreateNewInterface()){
					JavaClassDialog dialog = new JavaClassDialog(getShell(),model.getCurrentProject());
					if(model.getDaoInterfacePath() != null){
						dialog.setResourcePath(model.getDaoInterfacePath());
					}else{
						Table tb = ((BatisCommonWizard)getWizard()).getDtpFacade().getOperationalTable(model.getDtpStmt());
						if (tb != null)dialog.setDefaultName(model.getNamingConversion().getDAOInterfaceName(tb.getName()));
					}
					IPath select_path;
					if (dialog.open() == JavaClassDialog.OK && (select_path = dialog.getResourcePath()) != null){
						model.setDaoInterfacePath(select_path);
					}
				}else{
					IType existed_type = WorkspaceUtil.openType2(getShell(), model.getCurrentProject(), true);
					if (existed_type == null) return;
					if (!validateLocal(existed_type)){
						MessageDialog.openWarning(getShell(), "Waring", existed_type.getElementName()+" is not a local class");
						return;
					}
					model.setDaoInterfacePath(existed_type.getResource().getFullPath());
				}
			}
		});
		
		Label lblNewLabel = new Label(grpDaoSettings, SWT.NONE);
		FormData fd_lblNewLabel = new FormData();
		fd_lblNewLabel.right = new FormAttachment(0, 100);
		fd_lblNewLabel.top = new FormAttachment(lblInterface,10);
		lblNewLabel.setLayoutData(fd_lblNewLabel);
		lblNewLabel.setText("Implementation");
		
		text_impl_path = new Text(grpDaoSettings, SWT.BORDER);
		FormData fd_text_impl_path = new FormData();
		fd_text_impl_path.top = new FormAttachment(text_interface_path, 8);
		fd_text_impl_path.right = new FormAttachment(65);
		fd_text_impl_path.left = new FormAttachment(lblNewLabel,10);
		text_impl_path.setLayoutData(fd_text_impl_path);
		text_impl_path.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseDoubleClick(MouseEvent e) {
				if (model.getDaoCreateNewImplementation()){
					JavaClassDialog dialog = new JavaClassDialog(getShell(),model.getCurrentProject());
					if(model.getDaoImplementationPath() != null) {
						dialog.setResourcePath(model.getDaoImplementationPath());
					}else{
						Table tb = ((BatisCommonWizard)getWizard()).getDtpFacade().getOperationalTable(model.getDtpStmt());
						if (tb != null)dialog.setDefaultName(model.getNamingConversion().getDAOImplName(tb.getName()));
					}
					IPath select_path;
					if (dialog.open() == JavaClassDialog.OK && (select_path = dialog.getResourcePath()) != null){
						model.setDaoImplementationPath(select_path);
					}
				}else{
					IType existed_type = WorkspaceUtil.openType2(getShell(), model.getCurrentProject(), false);
					if (existed_type == null) return;
					if (!validateLocal(existed_type)){
						MessageDialog.openWarning(getShell(), "Waring", existed_type.getElementName()+" is not a local class");
						return;
					}
					model.setDaoImplementationPath(existed_type.getResource().getFullPath());
				}
			}
		});
		
		btn_create_new_interface = new Button(grpDaoSettings, SWT.CHECK);
		FormData fd_btn_create_new_interface = new FormData();
		fd_btn_create_new_interface.top = new FormAttachment(btnEnableInterface, 10);
		fd_btn_create_new_interface.right = new FormAttachment(100);
		btn_create_new_interface.setLayoutData(fd_btn_create_new_interface);
		btn_create_new_interface.setText("New");
		
		btn_create_new_impl = new Button(grpDaoSettings, SWT.CHECK);
		FormData fd_btn_create_new_impl = new FormData();
		fd_btn_create_new_impl.top = new FormAttachment(btn_create_new_interface,10);
		fd_btn_create_new_impl.right = new FormAttachment(100);
		btn_create_new_impl.setLayoutData(fd_btn_create_new_impl);
		btn_create_new_impl.setText("New");
		
		comboInterfaceViewer = new ComboViewer(grpDaoSettings, SWT.NONE);
		comboInterface = comboInterfaceViewer.getCombo();
		comboInterface.setToolTipText("select a template");
		FormData fd_comboInterface = new FormData();
		fd_comboInterface.right = new FormAttachment(btn_create_new_interface, -5);
		fd_comboInterface.top = new FormAttachment(btnEnableInterface, 5);
		fd_comboInterface.left = new FormAttachment(text_interface_path,5);
		comboInterface.setLayoutData(fd_comboInterface);
		
		comboImplViewer = new ComboViewer(grpDaoSettings, SWT.NONE);
		Combo comboImplement = comboImplViewer.getCombo();
		comboImplement.setToolTipText("select a template");
		FormData fd_comboImplement = new FormData();
		fd_comboImplement.right = new FormAttachment(btn_create_new_impl, -5);
		fd_comboImplement.left = new FormAttachment(text_impl_path, 5);
		fd_comboImplement.top = new FormAttachment(comboInterface,5);
		comboImplement.setLayoutData(fd_comboImplement);
		
		Group grpSpringIntegeration = new Group(container, SWT.NONE);
		grpSpringIntegeration.setLayout(new GridLayout(3, false));
		grpSpringIntegeration.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
		grpSpringIntegeration.setText("Spring Integeration");
		
		btnIntegrateIntoSpring = new Button(grpSpringIntegeration, SWT.CHECK);
		btnIntegrateIntoSpring.setText("Integrate Into Spring");
		new Label(grpSpringIntegeration, SWT.NONE);
		new Label(grpSpringIntegeration, SWT.NONE);
		
		Label lblSpringConfigurationFile = new Label(grpSpringIntegeration, SWT.NONE);
		lblSpringConfigurationFile.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
		lblSpringConfigurationFile.setText("Spring Configuration File");
		
		textSpringConfig = new Text(grpSpringIntegeration, SWT.BORDER);
		textSpringConfig.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseDoubleClick(MouseEvent e) {
				OpenResourceDialog res_dialog = new OpenResourceDialog(getShell(), model.getConfigurationFile().getProject(), IResource.FILE);
				if (res_dialog.open() == OpenResourceDialog.OK){
					IFile res = (IFile) res_dialog.getFirstResult();
					if (res.getProject() != model.getConfigurationFile().getProject()){
						MessageDialog.openError(getShell(), "ERROR",res.toString()+" is not a local file !");
					}
					if (FileProber.isValidSpringConfigurationFile(res)){
						model.setSpringConfiguration(res);
					}else{
						MessageDialog.openError(getShell(), "ERROR", res.toString()+" is not a valid spring configuration file");
					}
				}
			}
		});
		textSpringConfig.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
		
		Button btnOpen = new Button(grpSpringIntegeration, SWT.NONE);
		btnOpen.setVisible(false);
		btnOpen.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				
			}
		});
		btnOpen.setText("Open");
		
		Label lblSpringTemplate = new Label(grpSpringIntegeration, SWT.NONE);
		lblSpringTemplate.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
		lblSpringTemplate.setText("Spring Template");
		
		comboSpringTplViewer = new ComboViewer(grpSpringIntegeration, SWT.NONE);
		Combo comboSpringTemplate = comboSpringTplViewer.getCombo();
		comboSpringTemplate.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
		new Label(grpSpringIntegeration, SWT.NONE);
		
		Label lblBeanId = new Label(grpSpringIntegeration, SWT.NONE);
		lblBeanId.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
		lblBeanId.setAlignment(SWT.RIGHT);
		lblBeanId.setText("Bean Id");
		
		textBeanId = new Text(grpSpringIntegeration, SWT.BORDER);
		textBeanId.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
		new Label(grpSpringIntegeration, SWT.NONE);
		
		comboInterfaceViewer.setContentProvider(new ArrayContentProvider());
		comboInterfaceViewer.setLabelProvider(new LabelProvider(){
			@Override
			public String getText(Object element) {
				URL tpl_url = (URL) element;
				String fp = tpl_url.getFile();
				Matcher matcher = MiscHelper.DAO_API_PATTERN.matcher(fp);
				return matcher.find() ? matcher.group(1) : fp;
			}
		});
		
		comboImplViewer.setContentProvider(new ArrayContentProvider());
		comboImplViewer.setLabelProvider(new LabelProvider(){
			@Override
			public String getText(Object element) {
				URL tpl_url = (URL) element;
				String fp = tpl_url.getFile();
				Matcher matcher = MiscHelper.DAO_IMPL_PATTERN.matcher(fp);
				return matcher.find() ? matcher.group(1) : fp;
			}
		});
	}
	protected boolean validateLocal(IType existed_type) {
		return existed_type.getResource() != null && existed_type.getResource().getProject() == model.getConfigurationFile().getProject();
	}
	@Override
	protected void doBinding(EMFDataBindingContext bindingContext) {
		super.doBinding(bindingContext);
		
		IObservableValue ob_btn_interface = SWTObservables.observeSelection(btnEnableInterface);
		IObservableValue ob_model_interface = BeansObservables.observeValue(model, BatisSettingModel.K_DAO_NEED_INTERFACE);
		bindingContext.bindValue(ob_btn_interface, ob_model_interface, null, null);
		
		IObservableValue text_interface_pathObserveEnabledObserveWidget = SWTObservables.observeEnabled(text_interface_path);
		bindingContext.bindValue(text_interface_pathObserveEnabledObserveWidget, ob_model_interface, null, null);
		
		
		IObservableValue btn_create_new_interfaceObserveEnabledObserveWidget = SWTObservables.observeEnabled(btn_create_new_interface);
		bindingContext.bindValue(btn_create_new_interfaceObserveEnabledObserveWidget, ob_model_interface, null, null);
		//
		IObservableValue btn_create_new_interfaceObserveSelectionObserveWidget = SWTObservables.observeSelection(btn_create_new_interface);
		IObservableValue modelDaoCreateNewInterfaceObserveValue = BeansObservables.observeValue(model, BatisSettingModel.K_DAO_CREATE_NEW_INTERFACE);
		bindingContext.bindValue(btn_create_new_interfaceObserveSelectionObserveWidget, modelDaoCreateNewInterfaceObserveValue, null, null);
		//
		IObservableValue btn_create_new_implObserveSelectionObserveWidget = SWTObservables.observeSelection(btn_create_new_impl);
		IObservableValue modelDaoCreateNewImplementationObserveValue = BeansObservables.observeValue(model, BatisSettingModel.K_DAO_CREATE_NEW_IMPLEMENTATION);
		bindingContext.bindValue(btn_create_new_implObserveSelectionObserveWidget, modelDaoCreateNewImplementationObserveValue, null, null);
		//
		
		
		
		IObservableValue daoInterfaceTemplateViewerObserveSingleSelection = ViewersObservables.observeSingleSelection(comboInterfaceViewer);
		IObservableValue modelBeanTemplateObserveValue = BeansObservables.observeValue(model, BatisSettingModel.K_DAO_INTERFACE_TEMPLATE);
		bindingContext.bindValue(daoInterfaceTemplateViewerObserveSingleSelection, modelBeanTemplateObserveValue, null, null);
		
		ISWTObservableValue ob_combo_interface_tpl = SWTObservables.observeEnabled(comboInterface);
		bindingContext.bindValue(ob_combo_interface_tpl, ob_btn_interface);
		
		
		
		//
		IObservableList modelDaoImplTemplatesObserveList = BeansObservables.observeList(Realm.getDefault(), model, BatisSettingModel.K_DAO_IMPL_TEMPLATES);
		
		comboImplViewer.setInput(modelDaoImplTemplatesObserveList);
		
		IObservableValue daoImplTemplateViewerObserveSingleSelection = ViewersObservables.observeSingleSelection(comboImplViewer);
		IObservableValue modelImplTemplateObserveValue = BeansObservables.observeValue(model, BatisSettingModel.K_DAO_IMPL_TEMPLATE);
		bindingContext.bindValue(daoImplTemplateViewerObserveSingleSelection, modelImplTemplateObserveValue, null, null);
		
		//Spring
		ObservableListContentProvider listContentProvider = new ObservableListContentProvider();
		IObservableMap observeMap = PojoObservables.observeMap(listContentProvider.getKnownElements(), URL.class, "file");
		comboSpringTplViewer.setLabelProvider(new ObservableMapLabelProvider(observeMap){
			@Override
			public String getText(Object element) {
				String fp = super.getText(element);
				Matcher matcher = MiscHelper.SPRING_PATTERN.matcher(fp);
				return matcher.find() ? matcher.group(1) : fp;
			}
		});
		comboSpringTplViewer.setContentProvider(listContentProvider);
		//
		IObservableList modelSpringTemplatesObserveList = BeansObservables.observeList(Realm.getDefault(), model, BatisSettingModel.K_SPRING_TEMPLATES);
		comboSpringTplViewer.setInput(modelSpringTemplatesObserveList);
		
		IObservableValue daoSpringTemplateViewerObserveSingleSelection = ViewersObservables.observeSingleSelection(comboSpringTplViewer);
		IObservableValue modelSpringTemplateObserveValue = BeansObservables.observeValue(model, BatisSettingModel.K_SPRING_TEMPLATE);
		bindingContext.bindValue(daoSpringTemplateViewerObserveSingleSelection, modelSpringTemplateObserveValue, null, null);
		
		ISWTObservableValue ob_control_enable_spring = SWTObservables.observeSelection(btnIntegrateIntoSpring);
		IObservableValue ob_model_enable_spring = BeansObservables.observeValue(model, BatisSettingModel.K_SPRING_INTEGRATE);
		
		bindingContext.bindValue(ob_control_enable_spring, ob_model_enable_spring);
		
		ISWTObservableValue ob_control_enable_confslist = SWTObservables.observeEnabled(textSpringConfig);
		bindingContext.bindValue(ob_control_enable_confslist, ob_model_enable_spring);
		
		ISWTObservableValue ob_control_enable_spring_tpls = SWTObservables.observeEnabled(comboSpringTplViewer.getControl());
		bindingContext.bindValue(ob_control_enable_spring_tpls, ob_model_enable_spring);
		
		ISWTObservableValue ob_control_enable_beanid = SWTObservables.observeEnabled(textBeanId);
		bindingContext.bindValue(ob_control_enable_beanid, ob_model_enable_spring);
		
		ISWTObservableValue ob_text_bean_id = SWTObservables.observeText(textBeanId, SWT.FocusOut);
		IObservableValue ob_model_bean_id = BeansObservables.observeValue(model, BatisSettingModel.K_SPRING_BEAN_ID);
		bindingContext.bindValue(ob_text_bean_id, ob_model_bean_id);
		
	}
}
